package com.tarzan.security.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tarzan.common.core.base.BaseResponse;
import com.tarzan.common.core.exception.ErrorCodesEnum;
import com.tarzan.common.core.utils.ResponseUtil;
import com.tarzan.redis.service.RedisService;
import com.tarzan.security.manager.TokenManager;
import com.tarzan.security.model.LoginUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/**
 * @Package com.tarzan.security.filter
 * @Title LoginFilter
 * @Description TODO 登录过滤器，继承UsernamePasswordAuthenticationFilter，对用户名密码进行登录校验
 * @Author liujinshan
 * @CreateTime 2021/7/9 14:50
 */
public class LoginFilter extends UsernamePasswordAuthenticationFilter {

    private static final Logger log = LoggerFactory.getLogger(UsernamePasswordAuthenticationFilter.class);

    private AuthenticationManager authenticationManager;

    private TokenManager tokenManager;

    private RedisService redisService;

    public LoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager,
                       RedisService redisService) {
        this.authenticationManager = authenticationManager;
        this.tokenManager = tokenManager;
        this.redisService = redisService;
        this.setPostOnly(false);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
    }

    /**
     * @title attemptAuthentication
     * @description TODO 校验用户名密码是否正确
     * @param request
     * @param response
     * @return org.springframework.security.core.Authentication
     * @author liujinshan
     * @data 2021/7/9 15:55
     */
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        try {
            LoginUser user = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class);
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @title successfulAuthentication
     * @description TODO 登陆成功后操作
     * @param req
     * @param res
     * @param chain
     * @param auth
     * @return void
     * @author liujinshan
     * @data 2021/7/9 15:21
     */
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
                                            Authentication auth){
        LoginUser user = (LoginUser) auth.getPrincipal();
        String token = tokenManager.createToken(user.getUsername());
        redisService.setList(user.getUsername(), user.getPermissions());
        ResponseUtil.out(res, BaseResponse.ok(token));
    }

    /**
     * @title unsuccessfulAuthentication
     * @description TODO 登陆失败
     * @param request
     * @param response
     * @param e
     * @return void
     * @author liujinshan
     * @data 2021/7/9 15:21
     */
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException e){
        // 这些对于操作的处理类可以根据不同异常进行不同处理
        if (e instanceof UsernameNotFoundException) {
            log.info("【登录失败】" + e.getMessage());
            //用户名不存在
            ResponseUtil.out(response, BaseResponse.error(ErrorCodesEnum.USER_DOES_NOT_EXIST_ERROR.code(),ErrorCodesEnum.USER_DOES_NOT_EXIST_ERROR.msg()));
            return;
        }
        if (e instanceof LockedException) {
            log.info("【登录失败】" + e.getMessage());
            //用户锁定
            ResponseUtil.out(response, BaseResponse.error(ErrorCodesEnum.USER_LOCK_ERROR.code(),ErrorCodesEnum.USER_LOCK_ERROR.msg()));
            return;
        }
        if (e instanceof BadCredentialsException) {
            log.info("【登录失败】" + e.getMessage());
            //密码错误
            ResponseUtil.out(response, BaseResponse.error(ErrorCodesEnum.PASSWORD_ERROR.code(),ErrorCodesEnum.PASSWORD_ERROR.msg()));
            return;
        }
        ResponseUtil.out(response, BaseResponse.error("500","登陆失败"));
    }
}
